import time

import requests
from django.http import JsonResponse, HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
import json
import re

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework import generics, permissions
from rest_framework import status
from django.utils import timezone
from django.conf import settings
import uuid


from util.myrediss import r
from util.myjwt import myjwt
from util.sms_utils import sms
from util.imgage_code import random_code, make_verify_image

import base64
from io import BytesIO
from util.baiduapi import BaiduApi
from urllib.parse import quote
from django.shortcuts import render, redirect
from django.db import transaction

from .alipaysdk import AliPaySDK

import logging
from decimal import Decimal
from django.db import models

from .models import User, Patient, RelationType, IdType, RechargeOrder, PaymentUrl, Sflogin
from .serializers import PatientCreateUpdateSerializer, RelationTypeSerializer, IdTypeSerializer, UserInfoSerializer, \
    PatientSerializer, RechargeOrderSerializer, PaymentUrlSerializer, SfLoginSerializer

logger = logging.getLogger(__name__)


@require_http_methods(["GET"])
def get_image_code(request):
    """
    生成并返回图片验证码
    
    参数:
        request: HTTP请求对象，需要包含uuid参数
        
    流程:
        1. 获取前端传递的uuid参数
        2. 生成4位随机验证码
        3. 将验证码存入Redis，过期时间300秒(5分钟)
        4. 根据验证码生成图片
        5. 返回图片数据
        
    返回:
        成功: 图片数据(image/jpeg)
        失败: JSON错误信息
    """
    try:
        uuid = request.GET.get('uuid')
        if not uuid:
            return JsonResponse({'code': 400, 'message': '缺少uuid参数'})
        # 生成新验证码
        code = random_code(4)
        # 存入 redis，key 用 uuid
        r.set_value_time(f'{uuid}', code, 300)
        # 生成图片
        image_data = make_verify_image(code)
        response = HttpResponse(image_data, content_type='image/jpeg')
        response['Access-Control-Allow-Origin'] = '*'
        return response
    except Exception as e:
        return JsonResponse({'code': 500, 'message': f'服务器错误：{str(e)}'})

@csrf_exempt
@require_http_methods(["POST"])
def send_verification_code(request):
    """
    发送短信验证码
    
    参数:
        request: HTTP请求对象，请求体应包含以下JSON数据:
            - mobile: 手机号码
            - image_code: 图片验证码
            - uuid: 图片验证码对应的uuid
            
    流程:
        1. 验证手机号格式
        2. 验证图片验证码是否正确
        3. 检查是否在1分钟内重复发送
        4. 生成短信验证码
        5. 调用短信服务发送验证码
        6. 将验证码存入Redis，过期时间300秒(5分钟)
        7. 删除已使用的图片验证码
        
    返回:
        成功: {'code': 200, 'message': '验证码发送成功'}
        失败: {'code': 4xx/5xx, 'message': 错误信息}
    """
    try:
        data = json.loads(request.body)
        mobile = data.get('mobile')
        image_code = data.get('image_code')
        uuid = data.get('uuid')
        if not mobile or not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'message': '手机号格式不正确'})
        if not uuid:
            return JsonResponse({'code': 400, 'message': '缺少uuid参数'})
        # 验证图片验证码（不区分大小写）
        stored_code = r.get_value(f'{uuid}')
        if not stored_code or stored_code.decode().lower() != image_code.lower():
            return JsonResponse({'code': 400, 'message': '图片验证码错误或已过期'})
        if r.get_value(f'sms_send_{mobile}'):
            return JsonResponse({'code': 400, 'message': '请1分钟后再试'})
        sms_code = sms.generate_code()
        success, message = sms.send_sms(mobile, sms_code)
        if success:
            r.set_value_time(f'sms_code_{mobile}', sms_code, 300)
            r.client.delete(f'{uuid}')
            return JsonResponse({'code': 200, 'message': '验证码发送成功'})
        else:
            return JsonResponse({'code': 500, 'message': f'验证码发送失败：{message}'})
    except Exception as e:
        return JsonResponse({'code': 500, 'message': f'服务器错误：{str(e)}'})

@csrf_exempt
@require_http_methods(["POST"])
def login(request):
    """
    用户登录/注册(一体化接口)
    
    参数:
        request: HTTP请求对象，请求体应包含以下JSON数据:
            - mobile: 手机号码
            - sms_code: 短信验证码
            
    流程:
        1. 验证手机号格式
        2. 验证短信验证码是否正确
        3. 根据手机号查找用户，不存在则自动创建(无密码注册)
        4. 生成JWT token，有效期7天
        5. 将token存入Redis，用于后续验证和控制退出登录
        6. 删除已使用的短信验证码
        
    返回:
        成功: {
            'code': 200, 
            'message': '注册成功'/'登录成功',
            'data': {
                'userid': 用户ID,
                'token': JWT令牌,
                'username': 用户名,
                'phone': 手机号
            }
        }
        失败: {'code': 4xx/5xx, 'message': 错误信息}
    """
    try:
        data = json.loads(request.body)
        phone = data.get('mobile')  # 前端传的还是mobile，但后端用phone
        sms_code = data.get('sms_code')

        if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
            return JsonResponse({'code': 400, 'message': '手机号格式不正确'})

        stored_sms_code = r.get_value(f'sms_code_{phone}')
        if not stored_sms_code or stored_sms_code.decode() != sms_code:
            return JsonResponse({'code': 400, 'message': '验证码错误或已过期'})

        # 查找用户，不存在则自动创建(无密码注册)
        user, created = User.objects.get_or_create(
            phone=phone,
            defaults={'username': f'user_{phone[-4:]}'}
        )

        # 生成token，添加过期时间
        token = myjwt.encode({
            'userid': user.id,
            'exp': int(time.time()) + 7 * 24 * 3600  # 7天过期
        })

        # 存储token到redis，用于验证用户是否退出登录
        r.set_value_time(f'user_token_{user.id}', token, 7 * 24 * 3600)  # 7天过期

        # 删除短信验证码
        r.client.delete(f'sms_code_{phone}')

        return JsonResponse({
            'code': 200,
            'message': '注册成功' if created else '登录成功',
            'data': {
                'userid': user.id,
                'token': token,
                'username': user.username,
                'phone': user.phone
            }
        })
    except Exception as e:
        return JsonResponse({'code': 500, 'message': f'服务器错误：{str(e)}'})

@method_decorator(csrf_exempt, name='dispatch')
class UserInfoView(APIView):
    """
    用户信息获取API视图类
    使用DRF的APIView提供用户信息查询功能
    """
    
    def get(self, request):
        """
        获取用户信息
        
        参数:
            request: HTTP请求对象，需包含查询参数userid
            
        流程:
            1. 从请求中获取userid参数
            2. 查询用户是否存在
            3. 使用序列化器返回用户信息
            
        返回:
            成功: {'code': 200, 'data': 用户信息}
            失败: {'code': 4xx, 'message': 错误信息}
        """
        # 假设已登录用户id通过token获取，这里用request.GET.get('userid')举例
        userid = request.GET.get('userid')
        if not userid:
            return Response({'code': 400, 'message': '缺少用户ID'})
        try:
            user = User.objects.get(id=userid)
        except User.DoesNotExist:
            return Response({'code': 404, 'message': '用户不存在'})
        serializer = UserInfoSerializer(user)
        return Response({'code': 200, 'data': serializer.data})

@csrf_exempt
@require_http_methods(["POST"])
def logout(request):
    try:
        # 从request中获取用户信息（中间件添加的）
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return JsonResponse({'code': 401, 'message': '未登录'})
            
        # 从redis中删除token
        user_id = user_info.get('userid')
        r.client.delete(f'user_token_{user_id}')
        
        return JsonResponse({
            'code': 200,
            'message': '退出成功'
        })
    except Exception as e:
        return JsonResponse({'code': 500, 'message': f'服务器错误：{str(e)}'})

class PatientListCreateView(APIView):
    def get(self, request):
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({'code': 401, 'message': '未登录'})
        patients = Patient.objects.filter(user_id=user_info['userid'])
        serializer = PatientSerializer(patients, many=True)
        return Response({'code': 200, 'data': serializer.data})

    def post(self, request):
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({'code': 401, 'message': '未登录'})
        if Patient.objects.filter(user_id=user_info['userid']).count() >= 5:
            return Response({'code': 400, 'message': '最多只能添加5位就诊人'})
        data = request.data.copy()
        data['user'] = user_info['userid']
        serializer = PatientCreateUpdateSerializer(data=data)
        if serializer.is_valid():
            if data.get('is_default'):
                Patient.objects.filter(user_id=user_info['userid']).update(is_default=False)
            serializer.save()
            return Response({'code': 200, 'message': '添加成功'})
        return Response({'code': 400, 'message': serializer.errors})

class PatientRetrieveUpdateDestroyView(APIView):
    def get(self, request, pk):
        """获取单个就诊人信息"""
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({'code': 401, 'message': '未登录'})
        try:
            patient = Patient.objects.get(pk=pk, user_id=user_info['userid'])
            serializer = PatientSerializer(patient)
            return Response({'code': 200, 'data': serializer.data})
        except Patient.DoesNotExist:
            return Response({'code': 404, 'message': '就诊人不存在'})

    def put(self, request, pk):
        """更新就诊人信息"""
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({'code': 401, 'message': '未登录'})
        try:
            patient = Patient.objects.get(pk=pk, user_id=user_info['userid'])
        except Patient.DoesNotExist:
            return Response({'code': 404, 'message': '就诊人不存在'})

        data = request.data.copy()
        data['user'] = user_info['userid']
        serializer = PatientCreateUpdateSerializer(patient, data=data, partial=True)
        
        if serializer.is_valid():
            # 如果设置为默认就诊人，需要将其他就诊人的默认状态取消
            if data.get('is_default'):
                Patient.objects.filter(user_id=user_info['userid']).exclude(pk=pk).update(is_default=False)
            serializer.save()
            return Response({'code': 200, 'message': '更新成功', 'data': serializer.data})
        return Response({'code': 400, 'message': serializer.errors})

    def delete(self, request, pk):
        """删除就诊人"""
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({'code': 401, 'message': '未登录'})
        try:
            patient = Patient.objects.get(pk=pk, user_id=user_info['userid'])
            # 如果删除的是默认就诊人，将第一个就诊人设为默认（如果存在）
            if patient.is_default:
                other_patient = Patient.objects.filter(user_id=user_info['userid']).exclude(pk=pk).first()
                if other_patient:
                    other_patient.is_default = True
                    other_patient.save()
            patient.delete()
            return Response({'code': 200, 'message': '删除成功'})
        except Patient.DoesNotExist:
            return Response({'code': 404, 'message': '就诊人不存在'})

@api_view(['GET'])
def relationtype_list(request):
    queryset = RelationType.objects.all()
    serializer = RelationTypeSerializer(queryset, many=True)
    return Response({'code': 200, 'data': serializer.data})

@api_view(['GET'])
def idtype_list(request):
    queryset = IdType.objects.all()
    serializer = IdTypeSerializer(queryset, many=True)
    return Response({'code': 200, 'data': serializer.data})

class DingTalkLogin(APIView):
    def get(self, request):
        from urllib.parse import quote
        params = [
            f"redirect_uri={quote('http://localhost:8000/user/dd/callback/')}",
            "response_type=code",
            "client_id=ding8nfthp9uuysffqlw",
            "scope=openid",
            "prompt=consent"
        ]
        url = "https://login.dingtalk.com/oauth2/auth?" + ("&".join(params))
        return Response({"url": url})


class DingTalkCallback(APIView):
    def get(self, request):
        authCode = request.query_params.get('code')

        if not authCode:
            return Response({"code": 400, "message": "缺少授权码"})

        # 获取 accessToken
        data = {
            "clientId": "ding8nfthp9uuysffqlw",
            "clientSecret": "g1OWeYyyNa2LfkMK_56ULzqaosczob3LS_YIru-7hG4y0GJ3eAmsZx6hbWpd6iOX",
            "code": authCode,
            "grantType": "authorization_code"
        }

        try:
            resp = requests.post(
                'https://api.dingtalk.com/v1.0/oauth2/userAccessToken',
                json=data
            ).json()
            access_token = resp.get('accessToken')
            if not access_token:
                return Response({"code": 500, "message": "获取 accessToken 失败", "data": resp})
        except Exception as e:
            return Response({"code": 500, "message": f"请求钉钉失败: {str(e)}"})

        # 获取用户信息
        headers = {"x-acs-dingtalk-access-token": access_token}
        user_info_resp = requests.get(
            'https://api.dingtalk.com/v1.0/contact/users/me',
            headers=headers
        ).json()

        name = user_info_resp.get('nick')
        phone = user_info_resp.get('mobile')  # 钉钉返回的手机号
        print("name:", name, "phone:", phone)
        uid = user_info_resp.get('openId')  # 用户唯一标识

        if not all([name, phone, uid]):
            return Response({"code": 400, "message": "钉钉用户信息不全", "data": user_info_resp})

        # 查询是否已存在该第三方登录记录
        sfl = Sflogin.objects.filter(uid=uid, types=1).first()

        if not sfl:
            # 检查是否已有相同手机号的用户
            user = User.objects.filter(phone=phone).first()
            print(user)
            if not user:
                # 创建新用户
                userinfo = {
                    "phone": phone,
                    "password": phone,
                    "username": name
                }
                us = UserInfoSerializer(data=userinfo)
                if us.is_valid():
                    user = us.save()
                else:
                    return Response({"code": 10002, "msg": us.errors})
            # 创建第三方登录记录
            sfinfo = {
                "types": 1,
                "token": access_token,
                "uid": uid,
                "userid": user.id
            }
            sfs = SfLoginSerializer(data=sfinfo)
            if sfs.is_valid():
                sfs.save()
            else:
                return Response({"code": 10003, "msg": sfs.errors})
        else:
            # 已有绑定，更新 token 即可
            user = sfl.userid
            sfl.token = access_token
            sfl.save()

        # 生成 JWT Token
        payload = {
            "userid": user.id,
            "username": user.username,
            "exp": int(time.time()) + 60 * 60 * 24 # 24小时过期
        }
        token = myjwt.encode(payload)

        # 存储token到redis
        r.set_value_time(f'user_token_{user.id}', token, 60 * 60 * 24)  # 24小时过期

        print("钉钉登录存入redis的token:", token, "user_id:", user.id)

        # 生成刷新 Token (2天)
        payload["exp"] = int(time.time()) + 60 * 60 * 24 * 2
        refresh_token = myjwt.encode(payload)

        return Response({
            "code": 200,
            "message": "登录成功",
            "data": {
                "userid": user.id,
                "token": token,
                "retoken": refresh_token,
                "username": user.username,
                "phone": user.phone
            }
        })



from qiniu import Auth
# 获取token
class qnToken(APIView):
    def get(self, request):
        access_key = 'cIZQnBWJ7ek5iCrE1UnwSg7qBiWaYBLWT5mEcFcX'
        secret_key = 'iUW62sUbBE-r0mLEX8Tk_RIT7C_k1DGd864CSik-'
        q = Auth(access_key, secret_key)
        # 要上传的空间
        bucket_name = 'zzzllzz'

        # 3600为token过期时间，秒为单位。3600等于一小时
        token = q.upload_token(bucket_name)
        return Response({"code": 10000, 'data': token})

class ImageOCRView(APIView):
    def post(self, request):
        try:
            # 获取七牛云图片URL
            image_url = request.data.get('image_url')
            if not image_url:
                return Response({'code': 400, 'message': '缺少图片URL'})
            
            # URL编码
            encoded_url = quote(image_url)
            
            # 调用百度OCR API
            baidu_api = BaiduApi()
            result = baidu_api.info(encoded_url)
            
            # 解析百度API返回的结果
            if isinstance(result, str):
                result = json.loads(result)
            
            # 提取识别文本
            if 'words_result' in result:
                text = '\n'.join([item['words'] for item in result['words_result']])
                return Response({
                    'code': 200,
                    'message': '识别成功',
                    'data': {
                        'text': text,
                        'raw_result': result
                    }
                })
            else:
                return Response({
                    'code': 500,
                    'message': '识别失败',
                    'data': result
                })
                
        except Exception as e:
            return Response({
                'code': 500,
                'message': f'服务器错误：{str(e)}'
            })

class GetRechargePayUrl(APIView):
    """获取充值支付链接"""
    
    def get(self, request):
        """获取充值支付链接"""
        try:
            # 获取参数
            patient_id = request.query_params.get("patient_id")
            amount = request.query_params.get("amount")
            
            if not patient_id or not amount:
                return Response({"code": 400, "msg": "缺少必要参数"})
                
            try:
                amount = float(amount)
                if amount <= 0:
                    return Response({"code": 400, "msg": "充值金额必须大于0"})
            except:
                return Response({"code": 400, "msg": "金额格式错误"})
                
            # 获取就诊人信息
            try:
                patient = Patient.objects.get(id=patient_id)
            except Patient.DoesNotExist:
                return Response({"code": 404, "msg": "就诊人不存在"})
                
            # 生成订单
            order_id = RechargeOrder.generate_order_id()
            
            # 创建充值订单
            recharge_order = RechargeOrder(
                order_id=order_id,
                patient=patient,
                amount=amount,
                status='pending',
                payment_method='alipay'
            )
            recharge_order.save()
            
            # 创建支付宝支付链接
            ali = AliPaySDK()
            payment_url = ali.page_pay(
                out_trade_no=order_id,
                total_amount=amount,
                subject=f"{patient.name}就诊人账户充值 - ¥{amount}"
            )
            
            # 保存支付URL
            payment_url_obj = PaymentUrl(
                order=recharge_order,
                url=payment_url
            )
            payment_url_obj.save()
            logger.info(f"创建支付链接: 订单ID={order_id}, URL={payment_url}")
            
            # 返回支付链接
            return Response({
                "code": 200,
                "msg": "获取支付链接成功",
                "data": {
                    "order_id": order_id,
                    "amount": amount,
                    "payment_url": payment_url
                }
            })
                
        except Exception as e:
            logger.error(f"创建充值订单失败: {str(e)}")
            return Response({"code": 500, "msg": f"创建充值订单失败: {str(e)}"})


class RechargePayResult(APIView):
    """处理充值支付结果"""
    
    def get(self, request):
        """处理支付宝同步返回的充值结果"""
        try:
            # 记录请求参数
            params = request.query_params.dict()
            logger.info(f"收到支付宝同步返回: {params}")
            
            # 验证签名
            ali = AliPaySDK()
            result = ali.check_sign(params.copy())  # 使用copy避免修改原始参数
            
            if not result:
                logger.error("支付宝返回结果验证失败")
                # 使用硬编码的URL，避免依赖settings
                return redirect('http://localhost:5173/payment/fail?error=verify_failed')
                
            # 获取订单号
            order_id = params.get("out_trade_no")
            trade_no = params.get("trade_no")
            timestamp = params.get("timestamp")
            
            if not order_id:
                logger.error("支付宝返回结果缺少订单号")
                return redirect('http://localhost:5173/payment/fail?error=missing_order_id')
                
            # 查询订单
            try:
                with transaction.atomic():
                    recharge_order = RechargeOrder.objects.select_for_update().get(order_id=order_id)
                    logger.info(f"找到订单: {order_id}, 状态: {recharge_order.status}, 金额: {recharge_order.amount}")
                    
                    # 如果订单已经处理过，直接跳转到成功页面
                    if recharge_order.status == 'paid':
                        logger.info(f"订单已处理过: {order_id}")
                        return redirect(f'http://localhost:5173/payment/success?order_id={order_id}')
                    
                    # 获取患者ID，用于日志记录
                    patient_id = recharge_order.patient_id
                    
                    # 更新订单状态
                    recharge_order.status = 'paid'
                    recharge_order.payment_time = timezone.now()
                    recharge_order.trade_no = trade_no
                    recharge_order.save()
                    logger.info(f"订单状态已更新: {order_id} -> paid")
                    
                    # 更新就诊人余额
                    patient = recharge_order.patient
                    old_balance = patient.price
                    patient.price += recharge_order.amount
                    patient.save()
                    
                    # 验证余额是否正确更新
                    patient.refresh_from_db()
                    new_balance = patient.price
                    
                    logger.info(f"充值成功: 订单ID={order_id}, 金额={recharge_order.amount}, 就诊人ID={patient.id}, 原余额={old_balance}, 现余额={new_balance}")
                    
                    # 额外检查余额是否正确增加
                    expected_balance = old_balance + recharge_order.amount
                    if new_balance != expected_balance:
                        logger.error(f"余额更新异常: 期望={expected_balance}, 实际={new_balance}")
                    
                    # 删除支付URL
                    try:
                        payment_url = PaymentUrl.objects.get(order_id=order_id)
                        payment_url.delete()
                        logger.info(f"删除支付链接: 订单ID={order_id}")
                    except PaymentUrl.DoesNotExist:
                        logger.warning(f"支付链接不存在: 订单ID={order_id}")
                
                # 跳转到成功页面
                return redirect(f'http://localhost:5173/payment/success?order_id={order_id}')
                    
            except RechargeOrder.DoesNotExist:
                logger.error(f"订单不存在: {order_id}")
                return redirect('http://localhost:5173/payment/fail?error=order_not_found')
                
        except Exception as e:
            logger.error(f"处理支付宝同步返回失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return redirect('http://localhost:5173/payment/fail?error=unknown_error')

            
class RechargePayNotify(APIView):
    """处理支付宝异步通知"""
    
    def post(self, request):
        """处理支付宝异步通知"""
        try:
            # 获取通知数据
            notify_data = request.data.dict() if hasattr(request.data, 'dict') else request.data
            logger.info(f"收到支付宝异步通知: {notify_data}")
            
            # 验证签名
            ali = AliPaySDK()
            if not ali.check_sign(notify_data.copy()):  # 使用copy避免修改原始数据
                logger.error("支付宝异步通知验证失败")
                return HttpResponse("fail")
            
            # 提取订单信息
            order_id = notify_data.get('out_trade_no')
            trade_no = notify_data.get('trade_no')
            trade_status = notify_data.get('trade_status')
            
            logger.info(f"异步通知订单信息: 订单ID={order_id}, 交易号={trade_no}, 交易状态={trade_status}")
            
            # 只处理交易成功的通知
            if trade_status != 'TRADE_SUCCESS':
                logger.warning(f"忽略非成功交易状态: {trade_status}")
                return HttpResponse("success")
            
            # 查询订单
            try:
                with transaction.atomic():
                    recharge_order = RechargeOrder.objects.select_for_update().get(order_id=order_id)
                    logger.info(f"异步通知找到订单: {order_id}, 状态: {recharge_order.status}, 金额: {recharge_order.amount}")
                    
                    # 如果订单已经处理过，直接返回成功
                    if recharge_order.status == 'paid':
                        logger.info(f"异步通知订单已处理过: {order_id}")
                        return HttpResponse('success')
                    
                    # 获取患者ID，用于日志记录
                    patient_id = recharge_order.patient_id
                    
                    # 更新订单状态
                    recharge_order.status = 'paid'
                    recharge_order.payment_time = timezone.now()
                    recharge_order.trade_no = trade_no
                    recharge_order.save()
                    logger.info(f"异步通知订单状态已更新: {order_id} -> paid")
                    
                    # 更新就诊人余额
                    patient = recharge_order.patient
                    old_balance = patient.price
                    patient.price += recharge_order.amount
                    patient.save()
                    
                    # 验证余额是否正确更新
                    patient.refresh_from_db()
                    new_balance = patient.price
                    
                    logger.info(f"异步通知充值成功: 订单ID={order_id}, 金额={recharge_order.amount}, 就诊人ID={patient.id}, 原余额={old_balance}, 现余额={new_balance}")
                    
                    # 额外检查余额是否正确增加
                    expected_balance = old_balance + recharge_order.amount
                    if new_balance != expected_balance:
                        logger.error(f"异步通知余额更新异常: 期望={expected_balance}, 实际={new_balance}")
                    
                    # 删除支付URL
                    try:
                        payment_url = PaymentUrl.objects.get(order_id=order_id)
                        payment_url.delete()
                        logger.info(f"删除支付链接: 订单ID={order_id}")
                    except PaymentUrl.DoesNotExist:
                        logger.warning(f"支付链接不存在: 订单ID={order_id}")
                    
            except RechargeOrder.DoesNotExist:
                logger.error(f"异步通知订单不存在: {order_id}")
                return HttpResponse('fail')
            
            # 返回成功，告诉支付宝不要再次通知
            return HttpResponse('success')
            
        except Exception as e:
            logger.error(f"处理支付宝异步通知失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return HttpResponse('fail')

class RechargeOrderQueryView(APIView):
    """查询充值订单接口"""
    
    def get(self, request):
        """获取充值订单信息
        
        支持以下查询参数：
        - order_id: 订单ID（精确匹配）
        - patient_id: 就诊人ID（精确匹配）
        - status: 订单状态（精确匹配）
        - start_date: 创建时间开始日期（格式：YYYY-MM-DD）
        - end_date: 创建时间结束日期（格式：YYYY-MM-DD）
        
        如果未指定patient_id，将默认查询当前用户的默认就诊人的订单
        """
        try:
            # 获取当前用户信息
            user_info = getattr(request, 'user_info', None)
            if not user_info:
                return Response({"code": 401, "msg": "未登录"})
            
            # 获取查询参数
            order_id = request.query_params.get('order_id')
            patient_id = request.query_params.get('patient_id')
            status = request.query_params.get('status')
            start_date = request.query_params.get('start_date')
            end_date = request.query_params.get('end_date')
            
            # 如果未指定就诊人ID，则查询当前用户的默认就诊人
            if not patient_id:
                default_patient = Patient.objects.filter(
                    user_id=user_info['userid'], 
                    is_default=True
                ).first()
                
                if default_patient:
                    patient_id = default_patient.id
                    logger.info(f"未指定就诊人ID，使用默认就诊人: ID={patient_id}")
                else:
                    # 如果没有默认就诊人，尝试获取用户的第一个就诊人
                    first_patient = Patient.objects.filter(
                        user_id=user_info['userid']
                    ).first()
                    
                    if first_patient:
                        patient_id = first_patient.id
                        logger.info(f"未指定就诊人ID，使用第一个就诊人: ID={patient_id}")
                    else:
                        # 如果用户没有就诊人，返回空结果
                        logger.warning(f"用户没有就诊人: user_id={user_info['userid']}")
                        return Response({
                            "code": 200,
                            "msg": "查询成功",
                            "data": {
                                "total": 0,
                                "page": 1,
                                "size": 10,
                                "orders": []
                            }
                        })
            
            # 构建查询条件
            filters = {}
            
            if order_id:
                filters['order_id'] = order_id
            
            if patient_id:
                filters['patient_id'] = patient_id
            
            if status:
                filters['status'] = status
            
            if start_date:
                try:
                    start_datetime = timezone.datetime.strptime(start_date, '%Y-%m-%d')
                    start_datetime = timezone.make_aware(start_datetime)
                    filters['created_at__gte'] = start_datetime
                except ValueError:
                    return Response({"code": 400, "msg": "开始日期格式错误，正确格式为YYYY-MM-DD"})
            
            if end_date:
                try:
                    # 将结束日期设置为当天的23:59:59
                    end_datetime = timezone.datetime.strptime(end_date, '%Y-%m-%d')
                    end_datetime = timezone.make_aware(end_datetime)
                    end_datetime = end_datetime.replace(hour=23, minute=59, second=59)
                    filters['created_at__lte'] = end_datetime
                except ValueError:
                    return Response({"code": 400, "msg": "结束日期格式错误，正确格式为YYYY-MM-DD"})
            
            # 执行查询
            orders = RechargeOrder.objects.filter(**filters).order_by('-created_at')
            
            # 分页处理
            page = int(request.query_params.get('page', 1))
            size = int(request.query_params.get('size', 10))
            
            # 计算分页
            start = (page - 1) * size
            end = start + size
            
            # 获取总数
            total = orders.count()
            
            # 切片获取当前页数据
            current_page_orders = orders[start:end]
            
            # 序列化结果
            serializer = RechargeOrderSerializer(current_page_orders, many=True)
            
            # 添加统计信息
            result = {
                "code": 200,
                "msg": "查询成功",
                "data": {
                    "total": total,
                    "page": page,
                    "size": size,
                    "orders": serializer.data
                }
            }
            
            # 如果查询了就诊人ID，添加一些统计信息
            if patient_id:
                # 计算该就诊人的充值总额
                total_paid_amount = RechargeOrder.objects.filter(
                    patient_id=patient_id, 
                    status='paid'
                ).aggregate(
                    total=models.Sum('amount')
                ).get('total') or 0
                
                # 计算该就诊人的待支付订单数
                pending_count = RechargeOrder.objects.filter(
                    patient_id=patient_id, 
                    status='pending'
                ).count()
                
                # 添加到结果中
                result['data']['statistics'] = {
                    'total_paid_amount': total_paid_amount,
                    'pending_count': pending_count
                }
                
                # 添加就诊人信息
                try:
                    patient = Patient.objects.get(id=patient_id)
                    result['data']['patient'] = {
                        'id': patient.id,
                        'name': patient.name,
                        'balance': str(patient.price)
                    }
                except Patient.DoesNotExist:
                    pass
            
            return Response(result)
            
        except Exception as e:
            logger.error(f"查询充值订单失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response({"code": 500, "msg": f"查询充值订单失败: {str(e)}"})


class RechargeOrderDetailView(APIView):
    """充值订单详情接口"""
    
    def get(self, request, order_id):
        """获取指定订单的详细信息"""
        try:
            # 查询订单
            try:
                order = RechargeOrder.objects.get(order_id=order_id)
            except RechargeOrder.DoesNotExist:
                return Response({"code": 404, "msg": "订单不存在"})
            
            # 序列化
            serializer = RechargeOrderSerializer(order)
            
            return Response({
                "code": 200,
                "msg": "查询成功",
                "data": serializer.data
            })
            
        except Exception as e:
            logger.error(f"查询订单详情失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response({"code": 500, "msg": f"查询订单详情失败: {str(e)}"})

class PaymentUrlListView(APIView):
    """支付URL列表接口"""
    
    def get(self, request):
        """获取支付URL列表
        
        支持以下查询参数：
        - patient_id: 就诊人ID（关联订单的就诊人ID）
        """
        try:
            # 获取当前用户信息
            user_info = getattr(request, 'user_info', None)
            if not user_info:
                return Response({"code": 401, "msg": "未登录"})
            
            # 获取查询参数
            patient_id = request.query_params.get('patient_id')
            
            # 构建查询条件
            filters = {}
            
            # 如果指定了就诊人ID，则只查询该就诊人的支付URL
            if patient_id:
                filters['order__patient_id'] = patient_id
            else:
                # 如果没有指定就诊人ID，则查询当前用户所有就诊人的支付URL
                patients = Patient.objects.filter(user_id=user_info['userid']).values_list('id', flat=True)
                filters['order__patient_id__in'] = list(patients)
            
            # 只查询状态为待支付的订单的支付URL
            filters['order__status'] = 'pending'
            
            # 执行查询
            payment_urls = PaymentUrl.objects.filter(**filters).order_by('-created_at')
            
            # 分页处理
            page = int(request.query_params.get('page', 1))
            size = int(request.query_params.get('size', 10))
            
            # 计算分页
            start = (page - 1) * size
            end = start + size
            
            # 获取总数
            total = payment_urls.count()
            
            # 切片获取当前页数据
            current_page_urls = payment_urls[start:end]
            
            # 序列化结果
            serializer = PaymentUrlSerializer(current_page_urls, many=True)
            
            # 为了方便前端使用，返回更详细的信息
            result_data = []
            for item in serializer.data:
                order_id = item['order']
                try:
                    order = RechargeOrder.objects.get(order_id=order_id)
                    patient = order.patient
                    
                    result_data.append({
                        'order_id': order_id,
                        'url': item['url'],
                        'created_at': item['created_at'],
                        'amount': str(order.amount),
                        'patient_id': patient.id,
                        'patient_name': patient.name
                    })
                except (RechargeOrder.DoesNotExist, Patient.DoesNotExist):
                    # 如果订单或患者不存在，仍然返回基本信息
                    result_data.append({
                        'order_id': order_id,
                        'url': item['url'],
                        'created_at': item['created_at']
                    })
            
            return Response({
                "code": 200,
                "msg": "查询成功",
                "data": {
                    "total": total,
                    "page": page,
                    "size": size,
                    "payment_urls": result_data
                }
            })
            
        except Exception as e:
            logger.error(f"查询支付链接失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response({"code": 500, "msg": f"查询支付链接失败: {str(e)}"})


class PaymentUrlDetailView(APIView):
    """支付URL详情接口"""
    
    def get(self, request, order_id):
        """获取指定订单的支付URL"""
        try:
            # 获取当前用户信息
            user_info = getattr(request, 'user_info', None)
            if not user_info:
                return Response({"code": 401, "msg": "未登录"})
            
            # 验证订单是否属于当前用户
            try:
                order = RechargeOrder.objects.get(order_id=order_id)
                patient = order.patient
                
                # 检查患者是否属于当前用户
                if patient.user_id != user_info['userid']:
                    return Response({"code": 403, "msg": "您无权访问此订单"})
                
                # 检查订单状态
                if order.status != 'pending':
                    return Response({"code": 400, "msg": "只有待支付订单才有支付链接"})
                
                # 获取支付URL
                try:
                    payment_url = PaymentUrl.objects.get(order_id=order_id)
                    
                    # 构建响应数据
                    data = {
                        'order_id': order_id,
                        'url': payment_url.url,
                        'created_at': payment_url.created_at,
                        'amount': str(order.amount),
                        'patient_id': patient.id,
                        'patient_name': patient.name,
                        'status': order.status
                    }
                    
                    return Response({
                        "code": 200,
                        "msg": "查询成功",
                        "data": data
                    })
                    
                except PaymentUrl.DoesNotExist:
                    return Response({"code": 404, "msg": "支付链接不存在"})
                
            except RechargeOrder.DoesNotExist:
                return Response({"code": 404, "msg": "订单不存在"})
            
        except Exception as e:
            logger.error(f"查询支付链接详情失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response({"code": 500, "msg": f"查询支付链接详情失败: {str(e)}"})
    
    def delete(self, request, order_id):
        """删除指定订单的支付URL"""
        try:
            # 获取当前用户信息
            user_info = getattr(request, 'user_info', None)
            if not user_info:
                return Response({"code": 401, "msg": "未登录"})
            
            # 验证订单是否属于当前用户
            try:
                order = RechargeOrder.objects.get(order_id=order_id)
                patient = order.patient
                
                # 检查患者是否属于当前用户
                if patient.user_id != user_info['userid']:
                    return Response({"code": 403, "msg": "您无权操作此订单"})
                
                # 检查订单状态，只允许删除待支付订单
                if order.status != 'pending':
                    return Response({"code": 400, "msg": "只能删除待支付的订单"})
                
                # 获取支付URL
                try:
                    payment_url = PaymentUrl.objects.get(order_id=order_id)
                    
                    # 删除支付URL
                    payment_url.delete()
                    logger.info(f"手动删除支付链接: 订单ID={order_id}")
                    
                    # 默认删除未支付订单，除非明确指定不删除
                    if request.query_params.get('keep_order') != 'true':
                        order.delete()
                        logger.info(f"手动删除订单: 订单ID={order_id}")
                        return Response({"code": 200, "msg": "支付链接和订单已删除"})
                    
                    return Response({"code": 200, "msg": "支付链接已删除"})
                    
                except PaymentUrl.DoesNotExist:
                    # 如果支付链接不存在，但订单存在且是待支付状态，则直接删除订单
                    if order.status == 'pending':
                        order.delete()
                        logger.info(f"手动删除订单(无支付链接): 订单ID={order_id}")
                        return Response({"code": 200, "msg": "订单已删除"})
                    return Response({"code": 404, "msg": "支付链接不存在"})
                
            except RechargeOrder.DoesNotExist:
                return Response({"code": 404, "msg": "订单不存在"})
            
        except Exception as e:
            logger.error(f"删除支付链接失败: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response({"code": 500, "msg": f"删除支付链接失败: {str(e)}"})


